package org.agiletestplus.client;

import org.agiletestplus.client.objects.Project;
import org.agiletestplus.client.ui.CreateProjectPanel;
import org.agiletestplus.client.ui.HomePanel;
import org.agiletestplus.client.ui.ManageConfigurationsPanel;
import org.agiletestplus.client.ui.ProjectPanel;
import org.damour.base.client.BaseApplication;
import org.damour.base.client.BaseApplicationUI;
import org.damour.base.client.objects.PermissibleObject;
import org.damour.base.client.objects.User;
import org.damour.base.client.service.BaseServiceCache;
import org.damour.base.client.ui.IGenericCallback;
import org.damour.base.client.ui.buttons.ToolbarButton;
import org.damour.base.client.ui.dialogs.DialogBox;
import org.damour.base.client.ui.toolbar.ToolBar;
import org.damour.base.client.utils.ParameterParser;
import org.damour.base.client.utils.StringUtils;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;

public class AgileTestPlusApplication extends BaseApplicationUI {
  
  private DockLayoutPanel contentPanel;

  public void loggedOut() {
    super.loggedOut();
    getApplicationContentDeck().clear();
    contentPanel = null;
    loadHome(true);
  }

  public void setAuthenticatedUser(User user) {
    super.setAuthenticatedUser(user);
    // getApplicationContentDeck().clear();
    handleStartupParameters();
  }

  public void loadApplication() {

    if (DOM.getElementById("testContent") != null) {
      DOM.getElementById("testContent").removeFromParent();
    }

    // getApplicationContentDeck().setAnimationEnabled(false);

    // history listener
    History.addValueChangeHandler(new ValueChangeHandler<String>() {
      public void onValueChange(ValueChangeEvent<String> event) {
        handleStartupParameters();
      }
    });

    // set uncaught exception handler
    GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() {
      public void onUncaughtException(Throwable throwable) {
        String text = "Uncaught exception: ";
        while (throwable != null) {
          StackTraceElement[] stackTraceElements = throwable.getStackTrace();
          text += throwable.toString() + "\n";
          for (int i = 0; i < stackTraceElements.length; i++) {
            text += "    at " + stackTraceElements[i] + "\n";
          }
          throwable = throwable.getCause();
          if (throwable != null) {
            text += "Caused by: ";
          }
        }
        DialogBox dialogBox = new DialogBox(true, false);
        DOM.setStyleAttribute(dialogBox.getElement(), "backgroundColor", "#ABCDEF");
        System.err.print(text);
        text = text.replaceAll(" ", "&nbsp;");
        dialogBox.setHTML("<pre>" + text + "</pre>");
        dialogBox.center();
      }
    });

    // use a deferred command so that the handler catches onModuleLoad2() exceptions
    // DeferredCommand.addCommand(new Command() {
    // public void execute() {
    // }
    // });

    GWT.runAsync(new RunAsyncCallback() {

      public void onSuccess() {
        Timer keepAlive = new Timer() {
          public void run() {
            BaseServiceCache.getService().ping(new AsyncCallback<Void>() {
              public void onFailure(Throwable caught) {
              };

              public void onSuccess(Void result) {
              };
            });
          }
        };
        keepAlive.scheduleRepeating(120000);
      }

      public void onFailure(Throwable reason) {
      }
    });

  }

  public void handleStartupParameters() {
    final ParameterParser parser;

    if (!StringUtils.isEmpty(History.getToken())) {
      parser = new ParameterParser(History.getToken());
    } else if (!StringUtils.isEmpty(Window.Location.getQueryString())) {
      parser = new ParameterParser(Window.Location.getQueryString());
    } else {
      // parse url for "REST" style parameters
      // http://demo.sometests.com/view/take-test/id/12345/name/Test-Name-1.html which is the same as
      // http://demo.sometests.com?view=take-test&id=12345&name=Test-Name-1.html
      parser = new ParameterParser(ParameterParser.convertRESTtoQueryString(Window.Location.getPath()));
    }

    if (!StringUtils.isEmpty(parser.getParameter("view"))) {
      String view = parser.getParameter("view");
      if ("home".equalsIgnoreCase(view)) {
        loadHome(false);
      } else if ("createproject".equalsIgnoreCase(view)) {
        loadCreateProject(new Project(), false);
      } else if ("configurations".equalsIgnoreCase(view)) {
        loadConfigurations(false);
      } else if ("admin".equalsIgnoreCase(view)) {
        loadAdmin(false);
      }
    } else {
      // go home
      loadHome(false);
    }
  }

  public void customizeApplicationToolBarLeft(ToolBar toolbar) {
    toolbar.addFiller(50);
    toolbar.addPadding(20);

    ToolbarButton homeButton = new ToolbarButton("Home");
    homeButton.setCommand(new Command() {
      public void execute() {
        loadHome(true);
      }
    });
    homeButton.setTitle("Home");
    toolbar.add(homeButton);
    toolbar.addPadding(10);
    
    ToolbarButton createProjectButton = new ToolbarButton("Create Project");
    createProjectButton.setCommand(new Command() {
      public void execute() {
        loadCreateProject(new Project(), true);
      }
    });
    createProjectButton.setTitle("Create Project");
    toolbar.add(createProjectButton);
    toolbar.addPadding(10);
    
    ToolbarButton manageConfigsButton = new ToolbarButton("Manage Configurations");
    manageConfigsButton.setCommand(new Command() {
      public void execute() {
        loadConfigurations(true);
      }
    });
    manageConfigsButton.setTitle("Manage Configurations");
    toolbar.add(manageConfigsButton);
    toolbar.addPadding(10);

  }

  public void customizeApplicationToolBarRight(ToolBar toolbar) {
    toolbar.addFiller(50);
  }

  public void loadHome(boolean addHistoryItem) {
    if (addHistoryItem) {
      History.newItem("view=home", false);
    }
    GWT.runAsync(new RunAsyncCallback() {

      public void onSuccess() {
    	  HomePanel homePanel = null;
        if (homePanel == null) {
	    	IGenericCallback<Project> callback = new IGenericCallback<Project>() {
				@Override
				public void invoke(Project object) {
					loadProject(object, false);
				}
			};

        	
          homePanel = new HomePanel(callback);
          homePanel.setHeight("100%");
          homePanel.setWidth("100%");
        }
        Window.setTitle(BaseApplication.getMessages().getString("companyName", "Your Company") + " - " + " Home");

        prepareContentPanel(null);
        setupScroll(homePanel);
      }

      public void onFailure(Throwable reason) {
      }
    });
  }  
  
  public void loadConfigurations(boolean addHistoryItem) {
    if (addHistoryItem) {
      History.newItem("view=configurations", false);
    }
    GWT.runAsync(new RunAsyncCallback() {

      public void onSuccess() {
        ManageConfigurationsPanel configPanel = null;
        IGenericCallback<Project> callback = new IGenericCallback<Project>() {
          @Override
          public void invoke(Project object) {
            // don't think this is used yet
          }
        };
        configPanel = new ManageConfigurationsPanel(callback);
        configPanel.setHeight("100%");
        configPanel.setWidth("100%");
        Window.setTitle(BaseApplication.getMessages().getString("Manage Configurations"));
        prepareContentPanel(null);
        setupScroll(configPanel);
      }

      public void onFailure(Throwable reason) {
      }
    });
  }
  
  
  public void loadProject(final Project project, boolean addHistoryItem) {
	  
	  if (addHistoryItem) {
	      History.newItem("view=project", false); // we should specify the project loading?
	    }
	    GWT.runAsync(new RunAsyncCallback() {

	      public void onSuccess() {
	    	IGenericCallback<Project> callback = new IGenericCallback<Project>() {
				@Override
				public void invoke(Project object) {
					if (object != null) {
						loadCreateProject(project, false);
					} else {
						loadHome(false);
					}
				}
			};
	    	  
	    	  ProjectPanel projectPanel = new ProjectPanel(callback, project);
	    	  Window.setTitle("Project: " + project.getName());

	    	  prepareContentPanel(null);
	    	  setupScroll(projectPanel);
	      }

	      public void onFailure(Throwable reason) {
	      }
	    });
	  }  

  
  public void loadCreateProject(final Project project, boolean addHistoryItem) {
	  
	  if (addHistoryItem) {
	      History.newItem("view=createproject", false);
	    }
	    GWT.runAsync(new RunAsyncCallback() {

	      public void onSuccess() {
	    	IGenericCallback<Project> callback = new IGenericCallback<Project>() {
				@Override
				public void invoke(Project object) {
					if (object != null && object.getId() != null) {
						loadProject(object, false);
					} else {
						loadHome(false);
					}
				}
			};
	    	  
	    	  CreateProjectPanel createProjectPanel = new CreateProjectPanel(callback, project);
	    	  if (project.getId() == null) {
	    		  Window.setTitle("Create New Project");
	    	  } else {
	    		  Window.setTitle("Edit Project");
	    	  }

	    	  prepareContentPanel(null);
	    	  setupScroll(createProjectPanel);
	      }

	      public void onFailure(Throwable reason) {
	      }
	    });
	  }  

  
  final ScrollPanel scroll = new ScrollPanel();

  private ScrollPanel setupScroll(Widget widget) {
    scroll.setWidget(widget);
    DOM.setStyleAttribute(scroll.getElement(), "borderWidth", "0px 1px 1px 1px");
    DOM.setStyleAttribute(scroll.getElement(), "borderColor", "#aaaaaa");
    DOM.setStyleAttribute(scroll.getElement(), "borderStyle", "solid");
    return scroll;
  }  
  
  public void prepareContentPanel(PermissibleObject contentObject) {
    if (contentPanel == null) {
      contentPanel = new DockLayoutPanel(Unit.PX);
      getApplicationContentDeck().add(contentPanel);
      contentPanel.add(scroll);
    }
    int idx = getApplicationContentDeck().getWidgetIndex(contentPanel);
    getApplicationContentDeck().showWidget(idx);
    
  }
  
}
